if(!this.bf)this.bf = {};
// some detections
;(function () {
	// gb2312，Chrome和Opera会返回gbk，当前页面非UTF8编码的。推荐使用 UTF-8。
	(document.charset || document.characterSet).toLowerCase() != 'utf-8' && console.log('非 UTF-8 页面编码。推荐使用 UTF-8');
	
    var ua = this.userAgent.toLowerCase();
	
	this.isWebkit = /webkit/.test(ua);
	if(this.isWebkit)this.webkitVersion = Number(ua.match(/webkit\/(\d+\.\d+)/)[1]);
	
	this.isIE = [, ] != 0;
	if(this.isIE){
		this.isIE6 = /msie 6/.test(ua);// ie6.test(ua) && alert('不支持' +  ie6 + '浏览器');
		this.isIE7 = /msie 7/.test(ua);
		this.isIE8 = /msie 8/.test(ua);
		this.isIE9 = /msie 9/.test(ua);
	}
	
	this.isFF = /firefox/i.test(ua);
	
	// Androdi & iPhone Detect...
    this.isAndroid = ua.indexOf("android") != -1;
    this.is_iOS    = ua.indexOf("iphone") != -1 || ua.indexOf("ipod") != -1 || ua.indexOf("ipad") != -1;

    var regexp, osVer;
    if(this.isAndroid === true) {
        regexp = /(?!android\s+)[24]/i;
        osVer  = regexp.exec(ua);
        if(osVer === null)alert('虽为安卓机型，但不被支持，ua:' + ua);
        else {
            osVer = osVer[0];
            this.isAndroid_2 = (osVer == 2);
            this.isAndroid_4 = (osVer == 4);
        }
    }else if (this.is_iOS) {
        regexp = /(?!(?!iphone|ipod|iPad)\s+os\s+)\d(?!_\d_\d)/i;
        osVer  = regexp.exec(ua);
        if(osVer === null)alert('虽为iOS机型，但不被支持，ua:' + ua);
        else{
            osVer = osVer[0];

            this.is_iOS_4 = (osVer == 4);
            this.is_iOS_5 = (osVer == 5);
            this.is_iOS_6 = (osVer == 6);
        }
    }

}).call(window.navigator);

/**
 * 函数委托 参见 http://blog.csdn.net/zhangxin09/article/details/8508128
 * @return {Function}
*/
Function.prototype.delegate = function () {
    var self = this, scope = this.scope, args = arguments, aLength = arguments.length, fnToken = 'function';

    return function(){
        var bLength = arguments.length, Length = (aLength > bLength) ? aLength : bLength;

        // mission one:
        for (var i = 0; i < Length; i++)
            if (arguments[i])args[i] = arguments[i]; // 拷贝参数

        args.length = Length; // 在 MS jscript下面，arguments作为数字来使用还是有问题，就是length不能自动更新。修正如左:

        // mission two:
        for (var i = 0, j = args.length; i < j; i++) {
            var _arg = args[i];
            if (_arg && typeof _arg == fnToken && _arg.late == true)
                args[i] = _arg.apply(scope || this, args);
        }

        return self.apply(scope || this, args);
    };
};

// for All Browsers
;(function(){
	/*
		$$('div')(true);
		$$('div')(function(){alert(888);});
		$$('div')()();
		$$('div')()(function(div){console.log(div);});
	*/
	function _$(cssSelector, cfg){
		var parentEl = this;
		return function(handler){
			if(handler){// 单数
				var resultEl = parentEl.querySelector(cssSelector);
				// debugger;
				if(typeof handler == 'function' && resultEl)resultEl.onClk(handler);
				if(typeof handler == 'function' && !resultEl){
					if(!cfg || (cfg && !cfg.isAssert))
						throw '找不到该元素:{0}，不能登记事件！'.format(cssSelector);
				}
				return resultEl;
			}else{		// 多数
				var resultEls = parentEl.querySelectorAll(cssSelector);
				return function(eachFn, handler){
					if(handler || eachFn){
						for(var i = 0, j = resultEls.length; i < j; i++){
							if(eachFn){
								var _forResult = eachFn(resultEls[i], i, j, resultEls);
								
								if(_forResult === true)continue; // 使得 true = continue 来控制 for 循环	
								if(_forResult === false)break; // 使得 false = break 来控制 for 循环
							}
							if(handler)resultEls[i].onClk(handler);
						}
					}
					return resultEls;
				};
			}
		}
	}

	// IE8 没有开放 HTMLElemnt，不过，好在可以用其父类 Element 代替。
	var addElementMethod = {
		/**
		* 单击事件的快捷方式。
		* @param {Function}	eventHandler
		* @param {Boolean}	isUseCapture	是否冒泡 默认为 false
		*/
		onClk : function (eventHandler, isUseCapture) {
			this.addEventListener("click", eventHandler, isUseCapture);
		},

		$ : _$,
		
		up : function(tagName, className){
			var el = this.parentNode;
			tagName = tagName && tagName.toUpperCase();
			while(el){
				if(tagName && el.tagName == tagName)return el;
				if(className && el.className && ~el.className.indexOf(className))return el;
				el = el.parentNode;
			}
			return null;
		},
		
		/**
		* 轮回样式。
		* @param {String} cls 样式
		*/
		toggleCls : function (cls) {
			var _cls = this.className;
			var reg = new RegExp('\\s?\\b' + cls + '\\b');
			if (reg.test(_cls))
				this.className = _cls.replace(reg, '');// remove it
			else {
				// add it
				if (_cls === '') this.className = cls;
				else this.className += ' ' + cls;
			}
		},
		
		/**
		 * 增加元素样式。
		 * @param {String} cls
		 */
		addCls : function (cls) {
			var _cls = this.className;
			if (_cls.indexOf(cls) === -1) {
				// add it
				if (_cls === '')this.className = cls;
				else this.className += ' ' + cls;
			}
		},

		/**
		 * 移除元素样式。
		 * @param {String} cls
		 */
		removeCls : function (cls) {
			var _cls = this.className;
			var reg = new RegExp('\\s?\\b' + cls + '\\b', 'ig');
			if (reg.test(_cls)) 
				this.className = _cls.replace(reg, '');// remove it
		},
		
		getChildren: function(){
			return this.children || getChildren();
		},
		
		/**
		 * 对所有子元素进行操作
		 */
		queryChild : function(cssSelector){
			var children = this.querySelectorAll(cssSelector);
			if (children == null)
				return function(){console.log(cssSelector + '找不到任何子元素！');};
			
			return every.bind(children);
		},
		
		/**
		 * 对所有子元素登记单击事件
		 */
		regChildClick : function(cssSelector, chlickFn){
			return this.queryChild(cssSelector)(function(item){
				item.addEventListener('click', chlickFn);
			});
		},
		updateChild : function(cssSelector, html){
			return this.queryChild(cssSelector)(function(item){
				item.innerHTML = html;
			});
		},
		
		/**
		 * 获取子元素，有防止 null pointer 处理
		 */
		$ : function(arg){
			if(arguments.length > 1){ // all
				var els = this.querySelectorAll.call(this, arg);
				if(typeof arguments[1] == 'function'){
					return Array.prototype.forEach.call(els, arguments[1]);
				}else{
					return els;
				}
			}else if(typeof arg == 'string'){
				var el = this.querySelector.apply(this, arguments);
				return el || emptyObj;
			}else if(typeof arg == 'function'){
				this.addEventListener('click', arg);
			}
			
			return this;
		}
	};
	var emptyObj = {$:function(){}};
	bf.emptyObj = emptyObj;
	addElementMethod.query = addElementMethod.queryChild;
	addElementMethod.$click = addElementMethod.regChildClick;
	
	function every(fn){
		var children = this;
		for(var i = 0, j = children.length; i < j; i++){
			var returnValue = fn(children[i], i, j, children);
			if (returnValue === false)break;
			if (returnValue === true) continue;
		}
		
		return this;
	}
	
	for(var i in addElementMethod)Element.prototype[i] = addElementMethod[i];
	
	Element.prototype.on = Element.prototype.addEventListener;
})();

;(function(){
	// 统一返回 int
	function toInt(value){
		return (value == 'auto' || !value) ? 0 : window.parseFloat(value, 10);
	}
	
	var nullPoint = '没有该样式属性';
	
	// 读取器
	function get(attribute){
		if(attribute in this){
			var value = this[attribute];
			return toInt(value);
		}else throw nullPoint + attribute;
	}
	
	// 通常不能返回真实 的尺寸
	function getSizeByStyle(el, attribute){
		return get.call(el.style, attribute);
	}
	
	function getSizeByComputedStyle(el, attribute){
		var _CSSStyleDeclaration = window.getComputedStyle(el);
		return get.call(_CSSStyleDeclaration, attribute);
	}
	
	// 而getClientRects是多行文字区域的坐标偏移集合，在非IE浏览器下，只对inline的标签有反应。
	// getClientRects返回的其实是个数组，数组中有很多个类似getBoundingClientRect返回的对象。
	// getClientRects 返回一个TextRectangle集合，就是TextRectangleList对象。
	// 那么这个TextRectangle对象有什么用呢，用来开判断文本是否换行！或者说用来获取矩形区域相关的坐标偏移对象！
	function getSizeByClientRects(el, attribute){
		var _ClientRects = el.getClientRects();
		return get.call(_ClientRects, attribute);
	}
	
	// 返回的永远是最外框框的那个矩形区域相关的坐标偏移对象；
	function getSizeByBoundingClientRect(el, attribute){
		var _BoundingClientRect = el.getBoundingClientRect();
		return get.call(_BoundingClientRect, attribute);
	}
	
	function bindPrototype_getSizeByBoundingClientRect(arrtibute){
		return getSizeByBoundingClientRect(this, arrtibute);
	}
	
	var Element_prototype = {
		getLeft : bindPrototype_getSizeByBoundingClientRect.delegate('left'),
		getRight: bindPrototype_getSizeByBoundingClientRect.delegate('right'),
		getTop  : bindPrototype_getSizeByBoundingClientRect.delegate('left'),
		getBottom: bindPrototype_getSizeByBoundingClientRect.delegate('bottom'),
		setLeft : function(leftValue){
			this.style.left = leftValue + 'px';
		}
	};
	
	for(var i in Element_prototype)Element.prototype[i] = Element_prototype[i];
	
})();


;(function(exports){
	function onreadystatechange(event, cb, parseContentType){
		if(this.readyState === 4 && this.status === 200) {
			var data = null;
			var responseText = this.responseText.trim();

			switch(parseContentType){
				case 'text':
					data = this.responseText;
					break;
				case 'xml':
					break;
					data = this.responseXML;
				case 'json':
				default:
					data = JSON.parse(responseText);
			}
			cb(data, this);
		}
	}
	exports.data = {
		/**
		 * 	bf.data.get('http://localhost:8080/mml/service/news', {
				start : 0, 
				limit:3
			}, function(json){
				console.log(json);
			});
		 * @param url
		 * @param args
		 * @param cb
		 * @param cfg
		 */
		get : function(url, args, cb, cfg, isDELETE){
			cfg = cfg || {};
			url = bf.utils.json2url(args || {}, url);
			
			var xhr = new XMLHttpRequest();
			xhr.open(isDELETE ? 'DELETE' : 'GET', url);
			xhr.onreadystatechange = onreadystatechange.delegate(
					null, cb, cfg.parseContentType
			);
			xhr.send(null);
		},
		post : function(url, args, cb, cfg, isPUT){
			cfg = cfg || {};
			
			var xhr = new XMLHttpRequest();
			xhr.open(isPUT ? 'PUT' : 'POST', url);
			xhr.onreadystatechange = onreadystatechange.delegate(
					null, cb, cfg.parseContentType
			);
			xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			xhr.send(bf.utils.json2url(args || {}));
		},
		
		/**
		 * 设置一个全局的空函数，然后 AOP 一下. 获取回调的引用，不管在哪个闭包中
		 * 加载 callBackField 字段到请求参数
		 * @param url
		 * @param args
		 * @param cb
		 */
		jsonp : function(url, args, cb, cfg){
			var globalMethod_Token	= 'globalMethod_' + getRandom();
			
			if(!window.$$_jsonp)window.$$_jsonp = {};
			// Map<String, Function>
			window.$$_jsonp[globalMethod_Token] = cb;
			
			var scriptTag = document.createElement('script');

			args = args || {};
			args[cfg && cfg.callBackField || 'callBack'] = '$$_jsonp.' + globalMethod_Token; 
			
			scriptTag.src = bf.utils.json2url(args || {}, url);
			document.getElementsByTagName('head')[0].appendChild(scriptTag);
		}
	};
	
	function getRandom(){
		return parseInt(Math.random()*(200000-10000 + 1) + 10000); 
	}
	
	exports.data.delet = exports.data.get.delegate(null, null, null, null, true);
	exports.data.put   = exports.data.post.delegate(null, null, null, null, true);
})(bf);

/**
 * <Form> 标签和form.submit方法的回车提交在firefox下面不工作，因为FireFox不捕捉回车事件。
 */
bf.patch = {};
;(function(binding){
	binding.fixSubmit_on_enter_press = function (formEl){
		if(window.navigator.isFF){
			parent.document.addEventListener("keydown", function(e){
				if(e.keyCode == 13){
					e.preventDefault();
					e.returnValue = false; 
					e.stopPropagation();

					formEl.onsubmit && formEl.onsubmit();
					formEl.submit();
					
					return false;
				}
			}, true);
		}
	}
})(bf.patch);

bf.dom = {
		
	/**
	 * 优先查询 parent win 中的元素
	 * 有时后台中需要获取 顶部 元素，即 parent.xx
	 */
	getParentEl : (function(){
		var empty = {}; // 空对象，为避免空指针
		return function(cssSelector){
			return parent.document.querySelector(cssSelector) 
				|| document.querySelector(cssSelector) 
				|| empty;
		}
	})()
};